\tikzstyle{rec} = [draw, align=center,inner sep=0.7em]
\tikzstyle{rec thin} = [draw, align=center, minimum height=7em, minimum width=2.5em]
\tikzstyle{rec long} = [draw, minimum width=12em, minimum height=2.5em, align=center]
\tikzstyle{arr shape} = [draw=red!70,ultra thick, shape=single arrow, minimum height=3em, single arrow tip angle=90, single arrow head extend=0.5em, scale=0.5]
\tikzstyle{arr tri} = [draw=lightyellow1, -{Triangle[width = 18pt, length = 8pt]}, line width=0.6em]
\tikzstyle{call} = [draw, align=center, shape = rectangle callout, rounded corners, anchor=south, minimum height=2em]

\newcommand{\Xshift}{6em}
\begin{tikzpicture}
    % 节点
    \node[rec thin] (源语言) at (0,0) {源\\语\\言};
    \node[rec] (词法分析) at ([xshift=\Xshift]源语言) {词法\\分析};
    \node[rec] (语法分析) at ([xshift=\Xshift]词法分析) {语法\\分析};
    \node[rec] (语义分析) at ([xshift=\Xshift]语法分析) {语义\\分析};
    \node[rec] (优化处理) at ([xshift=\Xshift]语义分析) {优化\\处理};
    \node[rec] (代码生成) at ([xshift=\Xshift]优化处理) {代码\\生成};
    \node[rec thin] (目标语言) at ([xshift=\Xshift]代码生成) {目\\标\\语\\言};
    \node[rec long] (错误处理) at ([yshift=6.5em]语义分析) {错\ 误\ 处\ 理};
    \node [rec long] (符号表管理) at ([yshift=-6.5em]语义分析) {符\ 号\ 表\ 管\ 理};
    
    % 指向 错误处理 和 符号表管理 的箭头
    \path[<->] (错误处理) edge (词法分析.north) edge (语法分析.north) edge (语义分析.north) edge (优化处理.north) edge (代码生成.north);
    \path[<->] (符号表管理) edge (词法分析.south) edge (语法分析.south) edge (语义分析.south) edge (优化处理.south) edge (代码生成.south);
    
    % 背景虚线框
    \begin{pgfonlayer}{background}
        \node[draw, dotted, ultra thick ,fit=(词法分析) (代码生成),minimum height=7em, minimum width=29em] {};
    \end{pgfonlayer}
    
    % 箭头
    % Triangle在老版本中没有
    \draw [arr tri] (源语言.east) -- (词法分析.west);
    \draw [arr tri] (词法分析.east) -- (语法分析.west);
    \draw [arr tri] (语法分析.east) -- (语义分析.west);
    \draw [arr tri] (语义分析.east) -- (优化处理.west);
    \draw [arr tri] (优化处理.east) -- (代码生成.west);
    \draw [arr tri] (代码生成.east) -- (目标语言.west);	
    
    % 箭头
    % 可以用shape画箭头
    %\node[arr shape, minimum height=4em] at ([xshift=0.5em]源语言.east) {};
    %\node[arr shape] at ([xshift=2em]词法分析) {};
    %\node[arr shape] at ([xshift=2em]语法分析) {};
    %\node[arr shape] at ([xshift=2em]语义分析) {};
    %\node[arr shape] at ([xshift=2em]优化处理) {};
    %\node[arr shape, minimum height=4em] at ([xshift=-0.5em]目标语言.west) {};
    
    % 对话框
    % 在使用absolute pointer时候会有bug,需要库decorations.text
    \node[call, anchor=south east, callout absolute pointer={([xshift=1em]语法分析.east)}] (语法树) at ([xshift=-3em]符号表管理.west|-符号表管理.south) {语法树};
    \node[call, anchor=south west, callout absolute pointer={([xshift=1em]词法分析.east)}] (单词串) at (源语言.west|-语法树.south) {单词串\\TOKEN};
    
    \node[call, anchor=south west, callout absolute pointer={([xshift=1em]语义分析.east)}] (语义树) at 	([xshift=3em]符号表管理.east|-语法树.south) {语义树};
    \node[call, anchor=south east, callout absolute pointer={([xshift=1em]优化处理.east)}] (优化语义树) at 	(目标语言.east|-单词串.south) {优化\\语义树};

\end{tikzpicture}